package com.gopay.bis.manager.bank.expay;

import java.util.Date;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;

import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.dao.bankorder.BankContractInfoDAO;
import com.gopay.common.constants.bank.SpdbAdpayBankInfoEnum;
import com.gopay.common.constants.bank.SpdbConstants;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.domain.bank.spdb.adpay.SpdbAdPayBody;
import com.gopay.common.domain.bank.spdb.adpay.SpdbAdPayHeader;
import com.gopay.common.domain.bank.spdb.adpay.SpdbAdPayMessage;
import com.gopay.common.domain.bank.spdb.adpay.req.AcntCheckReq;
import com.gopay.common.domain.bank.spdb.adpay.req.SinContractReq;
import com.gopay.common.domain.bank.spdb.adpay.req.SinCutQueryReq;
import com.gopay.common.domain.bank.spdb.adpay.req.SinCutReq;
import com.gopay.common.domain.bank.spdb.adpay.res.SinCutQueryRes;
import com.gopay.common.domain.bis.BisBankContractInfo;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.businesses.ExPayService;
import com.gopay.remote.bank.businesses.SingInService;

/**
 * 浦发代扣报文组装
 * 
 * SpdbAdPayManager.java
 * @author jiangxiangjiao
 * @2016-11-8 
 */
public class SpdbAdPayManager {
    
    @Resource(name = "spdbConfig")
    private Map<String, String> spdbConfig;

    @Resource(name = "spdbAdPayServiceClient")
    private ExPayService spdbAdPayServiceClient;
    
    @Resource(name = "spdbAdPaySingInService")
    private SingInService spdbAdPaySingInService;
    
    @Resource(name = "bankContractInfoDAO")
    private BankContractInfoDAO bankContractInfoDAO;

    /**
     * 平台发送实名身份认证请求
     * 
     * @param message
     * @return
     * @throws GopayException
     */
    public Object certification(ExPayBaseMessage message) throws GopayException {
        
        AcntCheckReq acntCheck = new AcntCheckReq();
        acntCheck.setReqDate(new DateTime().toString("YYYYMMdd"));
        // 生成唯一系统流水号
        String serialNo = DateUtils.getLocalFullDateTime14().substring(0, 8) + getShortUuid();
        acntCheck.setReqTransID(serialNo);
        acntCheck.setIsVali("0");
        acntCheck.setAcntNo(message.getCardNo());
        acntCheck.setAcntType(spdbConfig.get("SPDB.ADPAY.CARDTYPE"));
        acntCheck.setAcntName(message.getCardHolder());
        acntCheck.setIDCardNo(message.getIdentityCode());
        acntCheck.setIDCardType(spdbConfig.get("SPDB.ADPAY.IDTYPE"));
        SpdbAdPayBody <AcntCheckReq>body = new SpdbAdPayBody<AcntCheckReq>();
        body.setInfo(acntCheck);
        SpdbAdPayMessage<SpdbAdPayBody<AcntCheckReq>> reqMsg = new SpdbAdPayMessage<SpdbAdPayBody<AcntCheckReq>>();
        reqMsg.setBody(body);
        reqMsg.setHeader(createHeader(SpdbConstants.SPDB_ADPAY_SINCONTRACT, message.getMerID()));
        reqMsg.setPayUrl(message.getPayUrl());
        BankLogUtils.printExPayManagerCertificationReturnLog(reqMsg);
        return spdbAdPayServiceClient.certification(reqMsg);
    }
    
    /**
     * 平台发送签约请求
     *
     * @param message
     * @return
     * @throws GopayException
     */
    public Object sign(ExPayBaseMessage message) throws GopayException {
        // 查表
        if (!checkContract(message)) {
            // 构建签约信息
            SinContractReq signContract = new SinContractReq();
            signContract.setReqDate(new DateTime().toString("YYYYMMdd"));
            // 生成唯一系统流水号
            String serialNo = DateUtils.getLocalFullDateTime14().substring(0, 8) + getShortUuid();
            signContract.setReqTransID(serialNo);
            signContract.setIsVali("0");   //  ???
            signContract.setAcntNo(message.getCardNo());
            signContract.setAcntType(spdbConfig.get("SPDB.ADPAY.CARDTYPE"));
            signContract.setAcntName(message.getCardHolder());
            signContract.setIDCardNo(message.getIdentityCode());
            signContract.setIDCardType(spdbConfig.get("SPDB.ADPAY.IDTYPE"));
            SpdbAdPayBody <SinContractReq>body = new SpdbAdPayBody<SinContractReq>();
            body.setInfo(signContract);
            SpdbAdPayMessage<SpdbAdPayBody<SinContractReq>> reqMsg = new SpdbAdPayMessage<SpdbAdPayBody<SinContractReq>>();
            reqMsg.setBody(body);
            reqMsg.setHeader(createHeader(SpdbConstants.SPDB_ADPAY_SINCONTRACT, message.getMerID()));
            reqMsg.setPayUrl(message.getPayUrl());
            BankLogUtils.printExPayManagerSignSendLog(reqMsg);
            // 插表
            updateContract(message);
           return spdbAdPayServiceClient.sign(message);
        }
        return null;
    }
    
    public SpdbAdPayHeader createHeader(String activityCode, String reqMerchantNo){
        SpdbAdPayHeader header = new SpdbAdPayHeader();
        header.setActionCode("0");
        header.setActivityCode(activityCode);
        // 请求渠道号 00-人工渠道;02-电子渠道;99-默认渠道
        header.setReqChannelNo(spdbConfig.get("SPDB.ADPAY.REQCHANNELNO"));
        //请求商户号 由浦发侧受托支付系统生成,需商户在银行侧进行签约入网登记
        header.setReqMerchantNo(reqMerchantNo);
        header.setReqDateTime(new DateTime().toString("YYYYMMddhhmmssSSS"));
        // 生成唯一系统流水号
        String serialNo = DateUtils.getLocalFullDateTime14().substring(0, 8) + getShortUuid();
        header.setReqSysID(serialNo);
        return header;
    }

    
    public static void main(String[] args) {
		System.out.println(new DateTime().toString("YYYYMMddHHmmssSSS"));
	}
    /**
     * 平台发送代扣请求
     * 
     * @param message
     * @return
     * @throws GopayException
     */
    public Object payment(ExPayBaseMessage message) throws GopayException {
        SinCutReq signCut = new SinCutReq();
        signCut.setReqDate(new DateTime().toString("YYYYMMdd"));
        signCut.setReqTransID(message.getBankOrderId());
        signCut.setAcntNo(message.getCardNo());
        signCut.setAcntType(spdbConfig.get("SPDB.ADPAY.CARDTYPE"));
        signCut.setTransAmount(message.getAmount().toString());
        signCut.setAcntName(message.getCardHolder());
        signCut.setIDCardNo(message.getIdentityCode());
        signCut.setIDCardType(spdbConfig.get("SPDB.ADPAY.IDTYPE"));
        
        SpdbAdpayBankInfoEnum bankInfo = SpdbAdpayBankInfoEnum.getBankInfoByBankCode(message.getBank());
        if(bankInfo.getBankCode().equals(SpdbAdpayBankInfoEnum.NOSUPPORT.getBankCode())){
        	throw new GopayException("浦发代扣暂时不支持该银行的业务：" + message.getBank());
        }
        signCut.setBankNo(bankInfo.getBankNo());
        signCut.setBankName(bankInfo.getBankName());
        signCut.setBankProv("310000");
        signCut.setBankCity("310000");
        signCut.setBankTelPhone(message.getMediaId());
        
        SpdbAdPayBody <SinCutReq>body = new SpdbAdPayBody<SinCutReq>();
        body.setInfo(signCut);
        SpdbAdPayMessage<SpdbAdPayBody<SinCutReq>> reqMsg = new SpdbAdPayMessage<SpdbAdPayBody<SinCutReq>>();
        reqMsg.setOutStlmCd(message.getOutStlmCd());
        reqMsg.setBody(body);
        reqMsg.setHeader(createHeader(SpdbConstants.SPDB_ADPAY_SINCUT, message.getMerID()));
        reqMsg.setPayUrl(message.getPayUrl());
        reqMsg.setPrivateKeyPath2nd(message.getPrivateKeyPath2nd());
        BankLogUtils.printExPayManagerPaymentSendLog(reqMsg);
        return spdbAdPayServiceClient.payment(reqMsg);
    }
    
    /**
     * 平台发送签到请求
     * 
     * @param message
     * @return
     * @throws GopayException
     */
    public Object SignIn(Object message) throws GopayException {
    	ExPayBaseMessage base = (ExPayBaseMessage)message;
    	
        SpdbAdPayMessage<SpdbAdPayBody<String>> reqMsg = new SpdbAdPayMessage<SpdbAdPayBody<String>>();
        BeanUtils.copyProperties(base, reqMsg);
        reqMsg.setHeader(createHeader(SpdbConstants.SPDB_ADPAY_DALIYSIGNKEY, base.getMerID()));
        BankLogUtils.printExPayManagerSignInSendLog(reqMsg);
        return spdbAdPaySingInService.signIn(reqMsg);
    }

    /**
     * 平台发送代扣查询请求
     * 
     * @param message
     * @return
     * @throws GopayException
     */
    public Object query(ExPayBaseMessage message) throws GopayException {
        // 跨行代扣查询
        SpdbAdPayMessage<SpdbAdPayBody<SinCutQueryReq>> msg = new SpdbAdPayMessage<SpdbAdPayBody<SinCutQueryReq>>();
        SpdbAdPayBody<SinCutQueryReq> body = new SpdbAdPayBody<SinCutQueryReq>();
        
        SinCutQueryReq sinCutQuery = new SinCutQueryReq();
        sinCutQuery.setOrgReqDate(DateUtils.strToStr(message.getOrderDate(), "yyyyMMddHHmmss", "yyyyMMdd"));
        sinCutQuery.setOrgReqTransID(message.getOutOrderId());
        
        body.setInfo(sinCutQuery);
        msg.setBody(body);
        msg.setHeader(createHeader(SpdbConstants.SPDB_ADPAY_SINCUTQUERY, message.getMerID()));
        msg.setPayUrl(message.getPayUrl());
        msg.setPrivateKeyPath2nd(message.getPrivateKeyPath2nd());
        BankLogUtils.printExPayManagerQuerySendLog(msg);

        SpdbAdPayMessage<SpdbAdPayBody<SinCutQueryRes>> resMsg = (SpdbAdPayMessage<SpdbAdPayBody<SinCutQueryRes>>) spdbAdPayServiceClient.queryOrder(msg);
        BankLogUtils.printExPayManagerQueryReturnLog(resMsg);
        return resMsg;
    }
    
    public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
            "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8",
            "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
            "U", "V", "W", "X", "Y", "Z" };
    
    public static String getShortUuid() {
        StringBuffer stringBuffer = new StringBuffer();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        for (int i = 0; i < 8; i++) {
            String str = uuid.substring(i * 4, i * 4 + 4);
            int strInteger = Integer.parseInt(str, 16);
            stringBuffer.append(chars[strInteger % 0x3E]);
        }

        return stringBuffer.toString();
    }
    
    /**
     * 检查是否已签约状态
     *
     * @param message
     * @return
     */
    public boolean checkContract(ExPayBaseMessage message) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());

        bisBankContractInfo = bankContractInfoDAO.getContractInfo(bisBankContractInfo);
        // 如果不存在信息，新建
        if (bisBankContractInfo == null) {
            newContract(message);
            return false;
        } else if (new Date().after(DateUtils.strToDate(bisBankContractInfo.getContractExpiryDate(), "yyyy-MM-dd"))) {
            // 如果过期
            return false;
        } else {
            return true;
        }
    }
    
    /**
     * 新建签约信息
     *
     * @param message
     * @return
     */
    public void newContract(ExPayBaseMessage message) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setContractState("01");
        bisBankContractInfo.setContractNumber("0");

        bankContractInfoDAO.insertBisBankContractInfo(bisBankContractInfo);
    }

    /**
     * 修改签约信息
     *
     * @param message
     * @return
     */
    public void updateContract(ExPayBaseMessage message) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setContractState("01");

        // 浦发代扣代扣签约有效期  待咨询后确定
        //String date = DateUtils.format(DateUtils.add(new Date(), Calendar.YEAR, 1), "yyyy-MM-dd");
        //bisBankContractInfo.setContractExpiryDate(date);

        bankContractInfoDAO.updateBisBankContractInfo(bisBankContractInfo);
    }

}
